package com.flying.invest.summary.service;

import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.flying.common.annotation.DaoCreate;
import com.flying.common.annotation.DaoQuery;
import com.flying.common.annotation.DaoRemove;
import com.flying.common.annotation.Transaction;
import com.flying.common.util.Codes;
import com.flying.common.util.DateUtils;
import com.flying.common.util.DateUtils.Field;
import com.flying.common.util.Utils;
import com.flying.framework.annotation.MethodInfo;
import com.flying.framework.annotation.Param;
import com.flying.framework.annotation.Service;
import com.flying.framework.context.ServiceContext;
import com.flying.framework.data.Data;
import com.flying.framework.model.ActionResult;
import com.flying.framework.model.ModelFactory;
import com.flying.framework.model.QueryResult;
import com.flying.framework.security.Principal;
import com.flying.framework.service.AbstractService;
import com.flying.invest.account.service.AccountService;
import com.flying.invest.assets.service.AssetsBlockService;
import com.flying.invest.assets.service.AssetsMarketService;
import com.flying.invest.assets.service.AssetsTypeService;
import com.flying.invest.invest.service.InvestmentTransactionService;
import com.flying.invest.summary.model.SummaryMoneyDaily;
import com.flying.invest.summary.model.SummaryMoneyDaily.SummaryType;

@Service(value="SummaryMoneyDailyService", desc="")
public class SummaryMoneyDailyService extends AbstractService{
    private final static DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    
    private AccountService accountService;
    private InvestmentTransactionService transactionService;
    public void setAccountService(AccountService s) {
    	this.accountService = s;
    }
    public void setInvestmentTransactionService(InvestmentTransactionService s) {
    	this.transactionService = s;
    }
        
	@MethodInfo("新增")
	@DaoCreate(entity=SummaryMoneyDaily.ENTITY_NAME)
	public SummaryMoneyDaily create(

			@Param(value=SummaryMoneyDaily.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.TYPE_ID, required=false,	desc="类型ID") Long type_id,
			@Param(value=SummaryMoneyDaily.MARKET_ID, required=false,	desc="市场ID") Long market_id,
			@Param(value=SummaryMoneyDaily.BLOCK_ID, required=false,	desc="板块ID") Long block_id,
			@Param(value=SummaryMoneyDaily.CURRENCY, required=true,	desc="币种") String currency,
			@Param(value=SummaryMoneyDaily.CURRENCY_RATE, required=false,	desc="汇率") Double currency_rate,
			
			@Param(value=SummaryMoneyDaily.SUM_FROM_DATE, required=false,	desc="起始日期") String sum_from_date,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="截止日期") String sum_date,
			@Param(value=SummaryMoneyDaily.SUMMARY_DATE, required=true,	desc="汇总日期") Date summary_date,
			@Param(value=SummaryMoneyDaily.SUMMARY_TYPE, required=true,	desc="汇总类型", enumClass=SummaryType.class) Integer summary_type,

			@Param(value=SummaryMoneyDaily.PERIOD_BUY_AMOUNT, required=false,	desc="买入金额") Double period_buy_amount,
			@Param(value=SummaryMoneyDaily.PERIOD_BUY_COUNT, required=false,	desc="买入笔数") Integer period_buy_count,
			@Param(value=SummaryMoneyDaily.PERIOD_SELL_AMOUNT, required=false,	desc="卖出金额") Double period_sell_amount,
			@Param(value=SummaryMoneyDaily.PERIOD_SELL_COUNT, required=false,	desc="卖出笔数") Integer period_sell_count,
			@Param(value=SummaryMoneyDaily.PERIOD_INIT_AMOUNT, required=false,	desc="期初市值") Double period_init_amount,
			@Param(value=SummaryMoneyDaily.TOTAL_AMOUNT, required=false,	desc="期末市值") Double total_amount,
			@Param(value=SummaryMoneyDaily.PERIOD_PROFIT, required=false,	desc="当期利润") Double period_profit,
			
			@Param(value=SummaryMoneyDaily.TOTAL_COST, required=false,	desc="总成本") Double total_cost,
			@Param(value=SummaryMoneyDaily.TOTAL_TAX, required=false,	desc="总税额") Double total_tax,
			@Param(value=SummaryMoneyDaily.TOTAL_PROFIT, required=false,	desc="总利润") Double total_profit,
			
			@Param(value=SummaryMoneyDaily.CREATE_TIME, required=false,	desc="创建时间") Date create_time
		
		) {
		
		return null;
	}

	@MethodInfo("创建用户日报")
	public ActionResult createDailySummaryByUserId(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null && p != null) {
			user_id = Long.parseLong(p.getId());
		}
		return this.createSummaryByUserId(user_id, SummaryType.DAILY.value());
	}

	@MethodInfo("创建用户周报")
	public ActionResult createWeeklySummaryByUserId(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null && p != null) {
			user_id = Long.parseLong(p.getId());
		}
		return this.createSummaryByUserId(user_id, SummaryType.WEEKLY.value());
	}

	@MethodInfo("创建用户月报")
	public ActionResult createMonthlySummaryByUserId(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null && p != null) {
			user_id = Long.parseLong(p.getId());
		}
		return this.createSummaryByUserId(user_id, SummaryType.MONTHLY.value());
	}

	@MethodInfo("创建用户报表")
	@Transaction
	public ActionResult createSummaryByUserId(
			@Param(value=SummaryMoneyDaily.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUMMARY_TYPE, required=true,	desc="汇总类型", enumClass=SummaryType.class) Integer summary_type
		) {
		final Date summary_from_date, summary_to_date, summary_to_date_pre;	//实际统计截止时间
		if(summary_type == SummaryType.DAILY.value()) {
			summary_from_date = DateUtils.parseDate(df.format(new Date()),"yyyy-MM-dd");
			summary_to_date = new Date();
			summary_to_date_pre = DateUtils.add(summary_from_date, Field.DATE, -1);
		} else if(summary_type == SummaryType.WEEKLY.value()) {
			summary_to_date = DateUtils.getLastDayOfWeek(new Date());
			summary_from_date = DateUtils.parseDate(df.format(DateUtils.getFirstDayOfWeek(new Date())),"yyyy-MM-dd");
			summary_to_date_pre = DateUtils.add(summary_from_date, Field.DATE, -1);
		} else {
			summary_from_date = DateUtils.parseDate(df.format(DateUtils.getFirstDayOfMonth(new Date())),"yyyy-MM-dd");
			summary_to_date = DateUtils.getLastDayOfMonth(new Date());
			summary_to_date_pre = DateUtils.add(summary_from_date, Field.DATE, -1);
		}
		final String sum_from_date = df.format(summary_from_date);
		final String sum_to_date = df.format(summary_to_date);
		//
		this.removeSummary(user_id, df.format(summary_to_date), summary_type);
		//投资项目
		final List<SummaryMoneyDaily> list = this.findSummaryMoneyByUserId(user_id, df.format(new Date())).getRows();
		list.stream().forEach(x -> {
			if(x.getTypeId() > 0 && (summary_type == SummaryType.WEEKLY.value() || summary_type == SummaryType.MONTHLY.value())) {
				x.setPeriodBuyAmount(0.0);
				x.setPeriodBuyCount(0);
				x.setPeriodSellAmount(0.0);
				x.setPeriodSellCount(0);
				List<SummaryMoneyDaily> trans = this.findSummaryTransactionByGroup(user_id, x.getTypeId(), x.getMarketId(), 
						x.getBlockId(), x.getCurrency(), new String[] {sum_from_date, sum_to_date}).getRows();
				for(SummaryMoneyDaily t: trans) {
					x.setPeriodBuyAmount(x.getPeriodBuyAmount() + t.getPeriodBuyAmount());
					x.setPeriodBuyCount(x.getPeriodBuyCount() + t.getPeriodBuyCount());
					x.setPeriodSellAmount(x.getPeriodSellAmount() + t.getPeriodSellAmount());
					x.setPeriodSellCount(x.getPeriodSellCount() + t.getPeriodSellCount());
				}
			}
			SummaryMoneyDaily pre = this.findDailyMoneyByUserId(x.getUserId(), x.getTypeId(), x.getMarketId(), 
					x.getBlockId(), x.getCurrency(), df.format(summary_to_date_pre), summary_type);
			var period_init_amount = pre.getTotalAmount() == null?0.0: pre.getTotalAmount();
			var pre_profit = pre.getTotalProfit() == null?0.0: pre.getTotalProfit();
			var period_profit = x.getTotalProfit() - pre_profit;
			this.create(x.getUserId(), x.getTypeId(), x.getMarketId(), x.getBlockId(), x.getCurrency(), x.getCurrencyRate(), 
					sum_from_date, sum_to_date, summary_to_date, summary_type,
					x.getPeriodBuyAmount(), x.getPeriodBuyCount(), x.getPeriodSellAmount(), x.getPeriodSellCount(), 
					period_init_amount, x.getTotalAmount(), period_profit,
					x.getTotalCost(), x.getTotalTax(), x.getTotalProfit(), 
					summary_to_date);
		});
		return ModelFactory.create(ActionResult.class, Codes.CODE, Codes.SUCCESS);
	}

	@MethodInfo("删除")
	@DaoRemove(entity=SummaryMoneyDaily.ENTITY_NAME)
	public ActionResult removeSummary(
			@Param(value=SummaryMoneyDaily.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=true,	desc="汇总日期") String sum_date,
			@Param(value=SummaryMoneyDaily.SUMMARY_TYPE, required=true,	desc="汇总类型", enumClass=SummaryType.class) Integer summary_type
		) {
		return null;
	}

	@MethodInfo("搜索")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, pageable=true, modelClass=SummaryMoneyDaily.class)
	public QueryResult<SummaryMoneyDaily> findAll(
			@Param(value=SummaryMoneyDaily.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.TYPE_ID, required=false,	desc="类型ID") Long type_id,
			@Param(value=SummaryMoneyDaily.MARKET_ID, required=false,	desc="市场ID") Long market_id,
			@Param(value=SummaryMoneyDaily.BLOCK_ID, required=false,	desc="板块ID") Long block_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date,
			@Param(value=Codes.PAGE_NUM, 	required=false, desc="分页页号，默认0") int page,
			@Param(value=Codes.PAGE_SIZE, 	required=false, desc="分页大小，默认10") int rows) {
		return null;
	}

	@MethodInfo("搜索")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, pageable=false, modelClass=SummaryMoneyDaily.class, 
		qsql="select * from v_summary_money_daily t")
	public QueryResult<SummaryMoneyDaily> findSummaryMoneyByUserId(
			@Param(value=SummaryMoneyDaily.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=true,	desc="汇总日期") String sum_date) {
		return null;
	}

	@SuppressWarnings("unchecked")
	@MethodInfo("搜索交易统计信息")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, pageable=false, modelClass=SummaryMoneyDaily.class, 
		qsql="select * from v_summary_transaction_type t")
	public QueryResult<SummaryMoneyDaily> findSummaryTransactionByGroup(
			@Param(value=SummaryMoneyDaily.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.TYPE_ID, required=true,	desc="类型ID") Long type_id,
			@Param(value=SummaryMoneyDaily.MARKET_ID, required=true,	desc="市场ID") Long market_id,
			@Param(value=SummaryMoneyDaily.BLOCK_ID, required=true,	desc="板块ID") Long block_id,
			@Param(value=SummaryMoneyDaily.CURRENCY, required=true,	desc="币种") String currency,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=true,	desc="汇总日期", tag="BETWEEN") String[] sum_date) {
		if(sum_date.length == 1) {
			sum_date = new String[] {sum_date[0], df.format(new Date())};
		}
		return ModelFactory.create(QueryResult.class, SummaryMoneyDaily.SUM_DATE, sum_date);
	}

	@MethodInfo("查询")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, single=true, throwsNotFoundException=true )
	public SummaryMoneyDaily findById(
			@Param(value=SummaryMoneyDaily.SUMMARY_ID, required=true,	desc="ID") Long summary_id
		) throws Exception {
		return null;
	}

	@MethodInfo("查询")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, pageable=false, modelClass=SummaryMoneyDaily.class, wsql="summary_type=0")
	public QueryResult<SummaryMoneyDaily> findByUserIdDaily(
			@Param(value=SummaryMoneyDaily.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=true,	desc="汇总日期") String sum_date
		) {
		return null;
	}

	@SuppressWarnings("unchecked")
	@MethodInfo("查询")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, pageable=false, modelClass=SummaryMoneyDaily.class, osql="ORDER BY sum_date desc")
	public QueryResult<SummaryMoneyDaily> findDailySummary(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date
		) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null && p != null) {
			user_id = Long.parseLong(p.getId());
		}
		return ModelFactory.create(QueryResult.class, 
				SummaryMoneyDaily.USER_ID, user_id);
	}

	@SuppressWarnings("unchecked")
	@MethodInfo("查询")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, pageable=false, modelClass=SummaryMoneyDaily.class, osql="ORDER BY sum_date desc")
	public QueryResult<SummaryMoneyDaily> findWeeklySummary(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date
		) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null && p != null) {
			user_id = Long.parseLong(p.getId());
		}
		return ModelFactory.create(QueryResult.class, 
				SummaryMoneyDaily.USER_ID, user_id);
	}

	@SuppressWarnings("unchecked")
	@MethodInfo("查询")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, pageable=false, modelClass=SummaryMoneyDaily.class, osql="ORDER BY sum_date desc")
	public QueryResult<SummaryMoneyDaily> findMonthlySummary(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date
		) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null && p != null) {
			user_id = Long.parseLong(p.getId());
		}
		return ModelFactory.create(QueryResult.class, 
				SummaryMoneyDaily.USER_ID, user_id);
	}

	@MethodInfo("查询，根据指定维度唯一日统计")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, single=true, throwsNotFoundException=false )
	protected SummaryMoneyDaily findDailyMoneyByUserId(
			@Param(value=SummaryMoneyDaily.USER_ID, required=true,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.TYPE_ID, required=false,	desc="类型ID") Long type_id,
			@Param(value=SummaryMoneyDaily.MARKET_ID, required=false,	desc="市场ID") Long market_id,
			@Param(value=SummaryMoneyDaily.BLOCK_ID, required=false,	desc="板块ID") Long block_id,
			@Param(value=SummaryMoneyDaily.CURRENCY, required=true,	desc="币种") String currency,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date,
			@Param(value=SummaryMoneyDaily.SUMMARY_TYPE, required=true,	desc="汇总类型", enumClass=SummaryType.class) Integer summary_type
		) {
		return null;
	}

	//
	public List<SummaryMoneyDaily> findReportData(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date,
			@Param(value="dimension", required=true,	desc="报表维度") String[] dimension) {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null && p != null) {
			user_id = Long.parseLong(p.getId());
		}
		if(sum_date == null) sum_date = df.format(new Date());
		List<SummaryMoneyDaily> sources = this.findByUserIdDaily(user_id, sum_date).getRows();
		List<SummaryMoneyDaily> res = Utils.newArrayList();
		for(SummaryMoneyDaily s: sources) {
			boolean matched = false;
			for(SummaryMoneyDaily t: res) {
				if(t.match(s, dimension)) {
					t.mergeMoney(s);
					matched = true;
				}
			}
			if(!matched) {
				s.reCalculate();
				res.add(s);
			}
		}
		return res;
	}

	@MethodInfo("资产类型分布")
	public Data findAssetsTypeReport(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date) {
		NumberFormat nf = NumberFormat.getNumberInstance();
		nf.setMaximumFractionDigits(2);
		List<SummaryMoneyDaily> list = this.findReportData(user_id, sum_date, new String[] {"type_id"});
		AssetsTypeService ns = module.getService(AssetsTypeService.class);
		List<Map<String, Object>> result = Utils.newArrayList();
		list.stream().forEach(x -> {
			Map<String, Object> r = Utils.newHashMap();
			String name = x.getTypeId() == 0?"现金":ns.findById(x.getTypeId()).getName();
			r.put("name", name+"："+nf.format(x.getTotalAmount())+"￥<br>占比");
			r.put("y", x.getTotalAmount());
			r.put("type_id", x.getTypeId());
			result.add(r);
		});
		return new Data(Codes.ROWS, result);
	}
	
	@MethodInfo("资产板块分布")
	public Data findAssetsBlockReport(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date) {
		NumberFormat nf = NumberFormat.getNumberInstance();
		nf.setMaximumFractionDigits(2);
		List<SummaryMoneyDaily> list = this.findReportData(user_id, sum_date, new String[] {"block_id"});
		AssetsBlockService ns = module.getService(AssetsBlockService.class);
		List<Map<String, Object>> result = Utils.newArrayList();
		list.stream().forEach(x -> {
			Map<String, Object> r = Utils.newHashMap();
			String name = x.getBlockId() == 0?"现金":ns.findById(x.getBlockId()).getName();
			r.put("name", name+"："+nf.format(x.getTotalAmount())+"￥<br>占比");
			r.put("y", x.getTotalAmount());
			result.add(r);
		});
		return new Data(Codes.ROWS, result);
	}

	@MethodInfo("资产市场分布")
	public Data findAssetsMarketReport(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id,
			@Param(value=SummaryMoneyDaily.SUM_DATE, required=false,	desc="汇总日期") String sum_date) {
		NumberFormat nf = NumberFormat.getNumberInstance();
		nf.setMaximumFractionDigits(2);
		List<SummaryMoneyDaily> list = this.findReportData(user_id, sum_date, new String[] {"market_id"});
		AssetsMarketService ns = module.getService(AssetsMarketService.class);
		List<Map<String, Object>> result = Utils.newArrayList();
		list.stream().forEach(x -> {
			Map<String, Object> r = Utils.newHashMap();
			String name = x.getMarketId() == 0?"现金":ns.findById(x.getMarketId()).getName();
			r.put("name", name+"："+nf.format(x.getTotalAmount())+"￥<br>占比");
			r.put("y", x.getTotalAmount());
			r.put("market_id", x.getMarketId());
			result.add(r);
		});
		return new Data(Codes.ROWS, result);
	}
	
	//
	@SuppressWarnings("unchecked")
	@MethodInfo("资产日报")
	@DaoQuery(entity=SummaryMoneyDaily.ENTITY_NAME, pageable=false, modelClass=SummaryMoneyDaily.class, osql="order by sum_date desc")
	public QueryResult<SummaryMoneyDaily> findCostAmountData(
			@Param(value=SummaryMoneyDaily.USER_ID, required=false,	desc="用户ID") Long user_id) throws Exception {
		Principal p = ServiceContext.getContext().getPrincipal();
		if(user_id == null) user_id = Long.parseLong(p.getId());
		return ModelFactory.create(QueryResult.class, 
				SummaryMoneyDaily.USER_ID, user_id);
	}
}